﻿using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace HostingRedisServer
{
    public static class RedisProcessKiller
    {
        /// <summary>
        /// 方法1: 通过端口查找并终止进程（推荐）
        /// </summary>
        public static async Task KillRedisByPort(int port, ILogger? logger = null)
        {
            await Task.Run(() =>
            {
                try
                {
                    logger?.LogInformation("通过端口 {Port} 查找 Redis 进程", port);

                    // 使用 netstat 查找占用端口的进程
                    var psi = new ProcessStartInfo
                    {
                        FileName = "cmd.exe",
                        Arguments = $"/c netstat -ano | findstr :{port} | findstr LISTENING",
                        UseShellExecute = false,
                        CreateNoWindow = true,
                        RedirectStandardOutput = true,
                        RedirectStandardError = true
                    };

                    using var process = Process.Start(psi);
                    if (process == null)
                    {
                        logger?.LogWarning("无法启动 netstat 命令");
                        return;
                    }

                    var output = process.StandardOutput.ReadToEnd();
                    process.WaitForExit();

                    if (string.IsNullOrWhiteSpace(output))
                    {
                        logger?.LogInformation("端口 {Port} 未被占用", port);
                        return;
                    }

                    // 解析输出，提取 PID
                    var lines = output.Split(new[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries);
                    var pids = lines
                        .Select(line => line.Trim().Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries))
                        .Where(parts => parts.Length >= 5)
                        .Select(parts => parts[^1]) // 最后一列是 PID
                        .Where(pid => int.TryParse(pid, out _))
                        .Select(int.Parse)
                        .Distinct()
                        .ToList();

                    logger?.LogInformation("找到 {Count} 个占用端口 {Port} 的进程", pids.Count, port);

                    foreach (var pid in pids)
                    {
                        try
                        {
                            var targetProcess = Process.GetProcessById(pid);
                            logger?.LogInformation("终止进程: PID={PID}, 名称={Name}",
                                pid, targetProcess.ProcessName);

                            KillProcessAndChildren(pid, logger);
                            targetProcess.Dispose();
                        }
                        catch (ArgumentException)
                        {
                            logger?.LogWarning("进程 {PID} 不存在或已退出", pid);
                        }
                        catch (Exception ex)
                        {
                            logger?.LogError(ex, "终止进程 {PID} 失败", pid);
                        }
                    }
                }
                catch (Exception ex)
                {
                    logger?.LogError(ex, "通过端口查找进程失败");
                }
            });
        }

        /// <summary>
        /// 方法2: 枚举所有进程并匹配名称
        /// </summary>
        public static void KillAllRedisProcessesByName(ILogger? logger = null)
        {
            try
            {
                var processes = Process.GetProcessesByName("redis-server");

                logger?.LogInformation("找到 {Count} 个 redis-server 进程", processes.Length);

                foreach (var process in processes)
                {
                    try
                    {
                        logger?.LogInformation("终止 Redis 进程: PID={PID}", process.Id);
                        KillProcessAndChildren(process.Id, logger);
                    }
                    catch (Exception ex)
                    {
                        logger?.LogError(ex, "终止进程 {PID} 失败", process.Id);
                    }
                    finally
                    {
                        process.Dispose();
                    }
                }
            }
            catch (Exception ex)
            {
                logger?.LogError(ex, "枚举进程失败");
            }
        }

        /// <summary>
        /// 方法3: 使用 taskkill 命令（多次尝试）
        /// </summary>
        public static async Task KillRedisWithTaskkill(ILogger? logger = null)
        {
            // 尝试 3 次，使用不同的参数组合
            var commands = new[]
            {
                "taskkill /F /IM redis-server.exe /T",           // 标准终止
                "taskkill /F /IM redis-server.exe",              // 不终止子进程
                "taskkill /F /FI \"IMAGENAME eq redis-server.exe\"" // 使用过滤器
            };

            foreach (var command in commands)
            {
                try
                {
                    logger?.LogInformation("执行命令: {Command}", command);

                    var psi = new ProcessStartInfo
                    {
                        FileName = "cmd.exe",
                        Arguments = $"/c {command}",
                        UseShellExecute = false,
                        CreateNoWindow = true,
                        RedirectStandardOutput = true,
                        RedirectStandardError = true
                    };

                    using var process = Process.Start(psi);
                    if (process == null) continue;

                    var output = await process.StandardOutput.ReadToEndAsync();
                    var error = await process.StandardError.ReadToEndAsync();
                    await process.WaitForExitAsync();

                    if (!string.IsNullOrEmpty(output))
                        logger?.LogInformation("输出: {Output}", output.Trim());

                    if (!string.IsNullOrEmpty(error) && !error.Contains("找不到"))
                        logger?.LogWarning("错误: {Error}", error.Trim());

                    await Task.Delay(500); // 等待进程真正退出
                }
                catch (Exception ex)
                {
                    logger?.LogError(ex, "执行 taskkill 命令失败");
                }
            }
        }

        /// <summary>
        /// 方法4: 使用 PowerShell 强制终止
        /// </summary>
        public static async Task KillRedisWithPowerShell(ILogger? logger = null)
        {
            try
            {
                logger?.LogInformation("使用 PowerShell 终止 Redis 进程");

                var psi = new ProcessStartInfo
                {
                    FileName = "powershell.exe",
                    Arguments = "-NoProfile -Command \"Get-Process redis-server -ErrorAction SilentlyContinue | Stop-Process -Force\"",
                    UseShellExecute = false,
                    CreateNoWindow = true,
                    RedirectStandardOutput = true,
                    RedirectStandardError = true
                };

                using var process = Process.Start(psi);
                if (process == null) return;

                var output = await process.StandardOutput.ReadToEndAsync();
                var error = await process.StandardError.ReadToEndAsync();
                await process.WaitForExitAsync();

                if (!string.IsNullOrEmpty(output))
                    logger?.LogInformation("PowerShell 输出: {Output}", output.Trim());

                if (!string.IsNullOrEmpty(error))
                    logger?.LogWarning("PowerShell 错误: {Error}", error.Trim());
            }
            catch (Exception ex)
            {
                logger?.LogError(ex, "使用 PowerShell 终止进程失败");
            }
        }

        /// <summary>
        /// 终止进程及其所有子进程（使用 Windows API）
        /// </summary>
        private static void KillProcessAndChildren(int pid, ILogger? logger)
        {
            try
            {
                // 使用 taskkill /T 参数终止进程树
                var psi = new ProcessStartInfo
                {
                    FileName = "cmd.exe",
                    Arguments = $"/c taskkill /F /PID {pid} /T",
                    UseShellExecute = false,
                    CreateNoWindow = true,
                    RedirectStandardOutput = true,
                    RedirectStandardError = true
                };

                using var process = Process.Start(psi);
                process?.WaitForExit(3000);

                // 验证进程是否已终止
                Task.Delay(500).Wait();
                try
                {
                    var targetProcess = Process.GetProcessById(pid);
                    if (!targetProcess.HasExited)
                    {
                        logger?.LogWarning("进程 {PID} 未能通过 taskkill 终止，尝试直接 Kill", pid);
                        targetProcess.Kill(true);
                    }
                    targetProcess.Dispose();
                }
                catch (ArgumentException)
                {
                    // 进程已不存在，成功
                    logger?.LogInformation("进程 {PID} 已成功终止", pid);
                }
            }
            catch (Exception ex)
            {
                logger?.LogError(ex, "终止进程 {PID} 及其子进程失败", pid);
            }
        }

        /// <summary>
        /// 综合方案：按优先级尝试所有方法（无需 System.Management）
        /// </summary>
        public static async Task KillAllRedisProcessesReliably(int? port = null, ILogger? logger = null)
        {
            logger?.LogInformation("========== 开始清理 Redis 进程 ==========");

            // 1. 如果指定了端口，优先通过端口终止
            if (port.HasValue)
            {
                logger?.LogInformation("步骤 1/5: 通过端口 {Port} 终止", port.Value);
                await KillRedisByPort(port.Value, logger);
                await Task.Delay(1000);
            }

            // 2. 枚举所有 redis-server 进程
            logger?.LogInformation("步骤 2/5: 枚举所有 redis-server 进程");
            KillAllRedisProcessesByName(logger);
            await Task.Delay(1000);

            // 3. 使用 taskkill 多次尝试
            logger?.LogInformation("步骤 3/5: 使用 taskkill 命令");
            await KillRedisWithTaskkill(logger);
            await Task.Delay(1000);

            // 4. 使用 PowerShell
            logger?.LogInformation("步骤 4/5: 使用 PowerShell");
            await KillRedisWithPowerShell(logger);
            await Task.Delay(1000);

            // 5. 最终验证
            logger?.LogInformation("步骤 5/5: 验证清理结果");
            var remaining = Process.GetProcessesByName("redis-server");

            if (remaining.Length > 0)
            {
                logger?.LogError("仍有 {Count} 个 Redis 进程残留！", remaining.Length);

                foreach (var p in remaining)
                {
                    try
                    {
                        logger?.LogError("残留进程: PID={PID}, 启动时间={StartTime}",
                            p.Id, p.StartTime);

                        // 最后的尝试：直接 Kill
                        p.Kill(true);
                        p.WaitForExit(2000);
                    }
                    catch (Exception ex)
                    {
                        logger?.LogError(ex, "无法终止进程 {PID}", p.Id);
                    }
                    finally
                    {
                        p.Dispose();
                    }
                }

                // 最终手段：批量终止所有同名进程
                logger?.LogWarning("执行最终清理手段");
                await ForcedKillAll(logger);
            }
            else
            {
                logger?.LogInformation("✓ 所有 Redis 进程已成功清理");
            }

            logger?.LogInformation("========== Redis 进程清理完成 ==========");
        }

        /// <summary>
        /// 最终手段：使用多种命令强制批量终止
        /// </summary>
        private static async Task ForcedKillAll(ILogger? logger)
        {
            var commands = new[]
            {
                "wmic process where \"name='redis-server.exe'\" delete",
                "powershell -Command \"Get-Process redis-server -ErrorAction SilentlyContinue | ForEach-Object { $_.Kill($true) }\"",
                "for /f \"tokens=2\" %i in ('tasklist ^| findstr redis-server.exe') do taskkill /F /PID %i"
            };

            foreach (var command in commands)
            {
                try
                {
                    logger?.LogInformation("执行强制清理: {Command}", command);

                    var psi = new ProcessStartInfo
                    {
                        FileName = "cmd.exe",
                        Arguments = $"/c {command}",
                        UseShellExecute = false,
                        CreateNoWindow = true,
                        RedirectStandardOutput = true
                    };

                    using var process = Process.Start(psi);
                    if (process != null)
                    {
                        await process.WaitForExitAsync();
                        await Task.Delay(1000);
                    }
                }
                catch (Exception ex)
                {
                    logger?.LogWarning(ex, "强制清理命令执行失败");
                }
            }
        }
    }
}
